package edu.bbu.cshu.wmpc.formalization.CCppSource;

import java.util.ArrayList;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import edu.bbu.cshu.wmpc.core.SourceCodeWmpc;
import edu.bbu.cshu.wmpc.formalization.Formalization;

/**
 * <ul>
 * <li><b><i>ConcrateCcppFormalization</i></b></li>
 * <li style="list-style: none;"></li>
 * <li style="list-style: none;">
 * Class that extends {@link Formalization} and implements its methods/functions specific C/C++ language
 * 
 * @author WMPC team
 * </li>
 * </ul>
 */
public class ConcrateCcppFormalization extends Formalization {
	/**
	 * <ul style="margin-top: 24px;">
	 * <li><b><i>ConcrateCcppFormalization</i></b></li>
	 * <li style="list-style: none;"></li>
	 * <li style="list-style: none;">
	 * <p style="margin-left: 7px;">{@code public ConcrateCcppFormalization(}{@link SourceCodeWmpc} {@code param)}</p>
	 * <br>	
	 * Constructor that sets the value of {@code source}.
	 * 
	 * @param param - the source code which type is {@code SourceCodeWmpc}
	 * </li>
	 * </ul>
	 */
	public ConcrateCcppFormalization(SourceCodeWmpc param) {
		this.source = param;
	}
		
	public void removeComments() {
		ArrayList<String> tmp = source.getOriginal(); // Original source code

		/* regex */
		Pattern p1 = Pattern
				.compile("(\\/\\*([^*]|(\\*+([^*/])))*\\*+/)|(//.*)"); // /*xyz*/
																		// |
																		// //xyz
		Pattern p2 = Pattern.compile("\\/\\*.*$"); // abc /*xyz
		Pattern p3 = Pattern.compile("^.*\\*\\/"); // xyz */ abc
		Pattern p4 = Pattern.compile("^([^*]|(\\*+([^*/]))|[^/])*"); // not
																		// comment
		String temp; // variable for actually line
		temp = new String();
		Matcher m1, m2, m3, m4;
		StringBuffer sb;
		int i = 0;

		while (i < tmp.size()) {
			temp = tmp.get(i);
			sb = new StringBuffer(temp.length());
			m1 = p1.matcher(temp);
			while (m1.find()) { // delete the whole comments in a line
				m1.appendReplacement(sb, Matcher.quoteReplacement(""));
			}
			m1.appendTail(sb);

			temp = sb.toString();

			tmp.set(i, temp);
			sb = new StringBuffer(temp.length());
			m2 = p2.matcher(temp);
			int j = i;

			if (m2.find()) { // delete the string after { bracket and find its }
								// pair
				m2.appendReplacement(sb, Matcher.quoteReplacement(""));
				m2.appendTail(sb);
				temp = sb.toString();
				tmp.set(i, temp);
				j++; // i+1 line
				m3 = p3.matcher(tmp.get(j)); // delete the string before }
												// bracket

				while (!m3.find()) {
					tmp.set(j, ""); // the whole line is comment => empty line
					j++;
					m3 = p3.matcher(tmp.get(j));
				}

				temp = tmp.get(j);
				sb = new StringBuffer(temp.length());
				m3.appendReplacement(sb, Matcher.quoteReplacement(""));
				m3.appendTail(sb);
				temp = sb.toString();
				i = j;
			}

			/* check again if there is whole comment */
			sb = new StringBuffer(temp.length());
			m1 = p1.matcher(temp);
			while (m1.find()) {
				m1.appendReplacement(sb, Matcher.quoteReplacement(""));
			}
			m1.appendTail(sb);

			tmp.set(i, temp);
			m4 = p4.matcher(tmp.get(i));

			if (m4.find()) { // if there is no comment we will go to the next
								// line
				tmp.set(i, temp);
				i++;
			}
		}
		source.setModified(tmp); // set the modified sourceCode which is without
									// comments
	}

	public void newLineBreaker() {
		ArrayList<String> tmp = new ArrayList<String>();
		String tempLine = new String(); // a temp line which preserve's a line
		for (int i = 0; i < source.getModified().size(); i++) {
			tempLine = source.getFromModified(i);
			if (tempLine.indexOf("};") != -1) {
				tmp.add(tempLine);
				source.addKey(tmp.size()-1, i);
			} else if ((tempLine.indexOf(";") != -1)
					&& tempLine.indexOf("{") == -1
					&& tempLine.indexOf("}") == -1
					&& tempLine.toUpperCase().indexOf(" FOR") == -1
					&& tempLine.toUpperCase().indexOf(" WHILE") == -1
					&& tempLine.toUpperCase().indexOf(" IF") == -1
					&& tempLine.toUpperCase().indexOf(" UNTIL") == -1
					&& tempLine.toUpperCase().indexOf(" CASE") == -1) {
				StringTokenizer strToken = new StringTokenizer(tempLine, ";");
				if (tempLine.indexOf(";") == tempLine.lastIndexOf(";")) {
					tmp.add(tempLine);
					source.addKey(tmp.size()-1, i);
				}
				else {
					while (strToken.hasMoreTokens() == true) {
						tmp.add(strToken.nextToken().toString() + ";");
						source.addKey(tmp.size()-1, i);
					}
				}
			} else if (tempLine.indexOf("{") != -1
					&& tempLine.indexOf(";") != -1 && tempLine.length() > 1
					&& tempLine.indexOf("}") == -1
					&& tempLine.toUpperCase().indexOf("CASE") == -1) {
				char[] charTemp = new char[tempLine.length()];
				String tempForCopy;
				tempLine.getChars(0, tempLine.indexOf("{") + 1, charTemp, 0);
				tempForCopy = new String(charTemp);
				tmp.add(tempForCopy);
				source.addKey(tmp.size()-1, i);
				StringBuffer strBuff = new StringBuffer(tempLine);
				tempLine = strBuff.replace(0, tempLine.indexOf("{") + 1, "")
						.toString();
				tmp.add(tempLine);
				source.addKey(tmp.size()-1, i);
			} else if (tempLine.indexOf("{") != -1
					&& tempLine.indexOf(";") != -1 && tempLine.length() > 1
					&& tempLine.indexOf("}") != -1
					&& tempLine.toUpperCase().indexOf("CASE") == -1) {
				char[] charTemp = new char[tempLine.length()];
				String tempForCopy;
				tempLine.getChars(0, tempLine.indexOf("{") + 1, charTemp, 0);
				tempForCopy = new String(charTemp);
				tmp.add(tempForCopy);
				source.addKey(tmp.size()-1, i);
				StringBuffer strBuff = new StringBuffer(tempLine);
				tempLine = strBuff.replace(0, tempLine.indexOf("{") + 1, "")
						.toString();
				if (tempLine.indexOf(" while") == -1) {
					tempLine = tempLine.replaceAll("}", "");
					tmp.add(tempLine);
					source.addKey(tmp.size()-1, i);
					tmp.add("}");
					source.addKey(tmp.size()-1, i);
				} else {
					StringTokenizer strToken = new StringTokenizer(tempLine,
							";");
					int index = 1;
					while (strToken.hasMoreTokens()) {
						String tmpForToken = strToken.nextToken();
						if (index < 2) {
							tmp.add(tmpForToken + ";");
							source.addKey(tmp.size()-1, i);
							index++;
						} else {
							tmp.add(tmpForToken);
							source.addKey(tmp.size()-1, i);
						}
					}
				}
			} else if (tempLine.indexOf("}") != -1
					&& tempLine.indexOf(";") != -1 && tempLine.length() > 1
					&& tempLine.indexOf("{") == -1
					&& tempLine.toUpperCase().indexOf("CASE") == -1) {
				char[] charTemp = new char[tempLine.length()];
				String tempForCopy;
				tempLine.getChars(0, tempLine.indexOf("}") + 1, charTemp, 0);
				tempForCopy = new String(charTemp);
				tmp.add(tempForCopy);
				source.addKey(tmp.size()-1, i);
				StringBuffer strBuff = new StringBuffer(tempLine);
				tempLine = strBuff.replace(0, tempLine.indexOf("}") + 1, "")
						.toString();
				tmp.add(tempLine);
				source.addKey(tmp.size()-1, i);
			} else if (tempLine.indexOf(";") != -1
					&& tempLine.toUpperCase().indexOf(" CASE") == -1) {
				char[] charTemp = new char[tempLine.length()];
				String tempForCopy;
				tempLine.getChars(0, tempLine.indexOf(")") + 1, charTemp, 0);
				tempForCopy = new String(charTemp);
				tmp.add(tempForCopy);
				source.addKey(tmp.size()-1, i);
				StringBuffer strBuff = new StringBuffer(tempLine);
				tempLine = strBuff.replace(0, tempLine.indexOf(")") + 1, "")
						.toString();
				if (tempLine.equals("")) {
					tmp.add(tempLine);
					source.addKey(tmp.size()-1, i);
				} else {
					tmp.add(tempLine);
					source.addKey(tmp.size()-1, i);
				}
				
			} else if (tempLine.toUpperCase().indexOf(" CASE") != -1
					&& tempLine.toUpperCase().indexOf(";") != -1) {
				char[] charTemp = new char[tempLine.length()];
				String tempForCopy;
				tempLine.getChars(0, tempLine.toUpperCase().indexOf(":") + 1,
						charTemp, 0);
				tempForCopy = new String(charTemp);
				tmp.add(tempForCopy);
				source.addKey(tmp.size()-1, i);
				StringBuffer strBuff = new StringBuffer(tempLine);
				tempLine = strBuff.replace(0,
						+tempLine.toUpperCase().indexOf(":") + 1, "")
						.toString();
				tmp.add(tempLine);
				source.addKey(tmp.size()-1, i);
			} else {
				tmp.add(tempLine.toString());
				source.addKey(tmp.size()-1, i);
			}
		}
		source.setModified(tmp);
	}

	public String removeQuates(String str) {
		// TODO Auto-generated method stub
		return str.replaceAll("[\"].*[\"]", "");
	}

	public String removeWhitespace(String str) {
		str = str.replaceAll("\\t", "");
		str = str.trim().replaceAll(" +", " ");
		if (str.trim().length() == 0)
			return "";
		return str;
	}

	
	public String removeImports(String str) {
		if (str != null) {
			if (str.toUpperCase().indexOf("#INCLUDE") != -1) {
				return "";
			}
			if (str.toUpperCase().indexOf("USING") != -1) {
				return "";
			}
			if (str.toUpperCase().indexOf("CLASS") != -1) {
				return "";
			}
			if (str.toUpperCase().indexOf("MAIN") != -1) {
				return "";
			}
			if (str.toUpperCase().indexOf("VOID") != -1) {
				return "";
			}
		}
		return str;
	}

	public String removeOutput(String str) {
		return str
				.replaceAll(
						"\\s*cout .*;$|\\s*cout<<.*;$|\\s*printf\\(.*;$|\\s*fprintf\\(.*;$|\\s*putchar\\(.*;$|\\s*puts\\(.*;$",
						"");
	}

	public String removeTryCatch(String str) {
		str = str.replaceAll("\\s+try\\s+|^try\\s+|\\s+try\\s*\\{|^try\\s*\\{",
				" TRY ");// search for try

		if (str.toUpperCase().contains(" TRY "))
			return "";

		str = str.replaceAll("\\s+catch\\s*\\(|^catch\\s*\\(", " CATCH ");// search
																			// for
																			// catch

		if (str.toUpperCase().contains(" CATCH "))
			return "";

		return str;
	}

	public String removeBeginEnd(String str) {
		return str;
	}

	public String removeInput(String str) {
		return str
				.replaceAll(
						"\\s*cin .*;$|\\s*cin>>.*;$|\\s*cin.getline.*;$|\\s*getline\\(.*;$|\\s*scanf\\(.*;$|\\s*fscanf\\(;$|\\s*getchar\\(.*;$|\\s*gets\\(.*;$",
						"");
	}

	public String handleVariables(String str) {
		if (str.matches("^#*[ ][A-Za-z0-9]*\\.{1}[A-Za-z0-9]*[ ]#*$")) {
			return str;
		}
		if (!str.matches("^[ ]*[A-Za-z0-9]*\\.{1}.*$")) {
			str = str.replaceAll("\\(|\\)", "");
			String tmp = "";
			int index = 0;
			if ((index = str.indexOf("if")) != -1) {
				tmp = str.substring(0, index + 2) + " ";
				str = str.substring(index + 3, str.length());
			} else if ((index = str.indexOf("while")) != -1) {
				tmp = str.substring(0, index + 5) + " ";
				str = str.substring(index + 6, str.length());
			} else if ((index = str.indexOf("for")) != -1) {
				tmp = str.substring(0, index + 3) + " ";
				str = str.substring(index + 4, str.length());
			} else if ((index = str.indexOf("switch")) != -1) {
				tmp = str.substring(0, index + 6) + " ";
				str = str.substring(index + 7, str.length());
			} else if ((index = str.indexOf("case")) != -1) {
				tmp = str.substring(0, index + 4) + " ";
				str = str.substring(index + 5, str.length());
			}
			String replacement = str.replaceAll(
					"[ ]?[A-Za-z0-9\\[\\]<>]+ [\\*A-Za-z0-9]+[ ]?", "var");
			replacement = replacement.replaceAll(
					"[ ]?[\\*A-Za-z0-9\\.\\(\\)\\[\\]\"\']+[ ]?", "var");

			return tmp + replacement;
		}
		return str;
	}

	protected String shortenVariables(String str) {
		return str.replaceAll("([\\W]?)([\\w]{4})([\\w]*)([\\W]?)", "$1$2$4");
	}
}
